import { Injectable } from '@nestjs/common';
import {
  ValidationArguments,
  ValidationOptions,
  ValidatorConstraint,
  ValidatorConstraintInterface,
  registerDecorator,
} from 'class-validator';
import { DataSource, ObjectType, Repository } from 'typeorm';

type Condition = {
  entity: ObjectType<any>;
  /**
   * 用于查询的比对字段,默认id
   */
  map?: string;
};

@ValidatorConstraint({ name: 'dataExist', async: true })
@Injectable()
export class DataExist implements ValidatorConstraintInterface {
  constructor(private readonly dataSource: DataSource) {}
  async validate(value: string, args?: ValidationArguments): Promise<boolean> {
    if (!value) return true;
    let map = 'id';
    let repo: Repository<ObjectType<any>>;
    if ('entity' in args.constraints[0]) {
      map = args.constraints[0].entity ?? map;
      repo = this.dataSource.getRepository(args.constraints[0].entity);
    } else {
      repo = this.dataSource.getRepository(args.constraints[0]);
    }
    const res = await repo.findOneBy({
      [map]: value,
    });

    return !!res;
  }
  defaultMessage(args: ValidationArguments) {
    const [relatedProperty] = args.constraints;
    return `${relatedProperty} and ${args.property} don't match`;
  }
}
export function DataExists(
  entity: Condition | ObjectType<any>,
  validationOptions?: ValidationOptions,
) {
  return (object: Record<string, any>, propertyName: string) => {
    registerDecorator({
      target: object.constructor,
      propertyName,
      options: validationOptions,
      constraints: [entity],
      validator: DataExist,
    });
  };
}
